﻿
namespace LightCAD.Drawing.Actions
{

    public class TransformAction : ITransformDrawer
    {

        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;
        protected CancellationTokenSource cts;
        protected bool isFinish;
        protected DocumentRuntime docRt;
        protected ViewportRuntime vportRt;
        protected IDocumentEditor docEditor;
        protected ICommandControl commandCtrl;
        private string blockName;
        private string CurrentTransform;
        private Vector2 insertPoint;
        private Vector2 basePoint;
        private List<LcElement> selectedElements;

        private InElementsInputer InElementsInputer { get; set; }
        private ElementSetInputer ElementInputers { get; set; }
        private ElementInputer ElementInputer { get; set; }
        private CmdTextInputer CmdTextInputer { get; set; }
        private PointInputer PointInputer { get; set; }
        static TransformAction()
        {
            CreateMethods = new LcCreateMethod[4];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "SCALE",
                Description = "缩放",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name=  "Step0", Options= "SCALE 选择对象:" },
                    new LcCreateStep { Name=  "Step1", Options= "SCALE 指定基点:" },
                    new LcCreateStep { Name=  "Step2", Options= "SCALE 指定比例因子或[复制(C) 参照(R)]:" },
                    new LcCreateStep { Name=  "Step3", Options= "SCALE 指定参照长度:" },
                    new LcCreateStep { Name=  "Step4", Options= "SCALE 指定新的长度或 [点(P)]:" },
                    new LcCreateStep { Name=  "Step4", Options= "SCALE 指定第一点:" },
                    new LcCreateStep { Name=  "Step4", Options= "SCALE 指定第二点:" },
                }
            };

            CreateMethods[1] = new LcCreateMethod()
            {
                Name = "ROTATE",
                Description = "旋转",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name=  "Step0", Options= "ROTATE 选择对象:" },
                    new LcCreateStep { Name=  "Step1", Options= "ROTATE 指定基点:" },
                    new LcCreateStep { Name=  "Step2", Options= "ROTATE 指定比例因子或[复制(C) 参照(R)]:" },
                    new LcCreateStep { Name=  "Step3", Options= "ROTATE 指定参照长度:" },
                    new LcCreateStep { Name=  "Step4", Options= "ROTATE 指定新的长度或 [点(P)]:" },
                    new LcCreateStep { Name=  "Step4", Options= "ROTATE 指定第一点:" },
                    new LcCreateStep { Name=  "Step4", Options= "ROTATE 指定第二点:" },
                }
            };

            CreateMethods[2] = new LcCreateMethod()
            {
                Name = "MOVE",
                Description = "平移",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name=  "Step0", Options= "MOVE 选择对象:" },
                    new LcCreateStep { Name=  "Step1", Options= "MOVE 指定基点:" },
                    new LcCreateStep { Name=  "Step2", Options= "MOVE 指定比例因子或[复制(C) 参照(R)]:" },
                    new LcCreateStep { Name=  "Step3", Options= "MOVE 指定参照长度:" },
                    new LcCreateStep { Name=  "Step4", Options= "MOVE 指定新的长度或 [点(P)]:" },
                    new LcCreateStep { Name=  "Step4", Options= "MOVE 指定第一点:" },
                    new LcCreateStep { Name=  "Step4", Options= "MOVE 指定第二点:" },
                }
            };

            CreateMethods[3] = new LcCreateMethod()
            {
                Name = "MIRROR",
                Description = "镜像",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name=  "Step0", Options= "MIRROR 选择对象:" },
                    new LcCreateStep { Name=  "Step1", Options= "MIRROR 指定基点:" },
                    new LcCreateStep { Name=  "Step2", Options= "MIRROR 指定比例因子或[复制(C) 参照(R)]:" },
                    new LcCreateStep { Name=  "Step3", Options= "MIRROR 指定参照长度:" },
                    new LcCreateStep { Name=  "Step4", Options= "MIRROR 指定新的长度或 [点(P)]:" },
                    new LcCreateStep { Name=  "Step4", Options= "MIRROR 指定第一点:" },
                    new LcCreateStep { Name=  "Step4", Options= "MIRROR 指定第二点:" },
                }
            };
        }
        public TransformAction(IDocumentEditor docEditor)
        {
            this.docEditor = docEditor;    
            this.docRt = docEditor.DocRt;
            this.vportRt = (docEditor as DrawingEditRuntime).ActiveViewportRt;
            this.commandCtrl=this.vportRt.CommandCtrl;
        }
        public TransformAction()
        {
        }

        public TransformAction SetViewport(ViewportRuntime vportRt)
        {
            this.vportRt = vportRt;
            return this;
        }

        public async void ScaleTransform(string[] args)
        {
            this.StartAction();
            this.CurrentTransform = "SCALE";
            Vector2 scalePoint = new Vector2();
            var curMethod = CreateMethods[0];
            bool copy = false;
            this.ElementInputers = new ElementSetInputer(this.docEditor);
            this.CmdTextInputer = new CmdTextInputer(this.docEditor);
            this.PointInputer = new PointInputer(this.docEditor);
            double length = 0;
            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                this.selectedElements = this.docRt.Action.SelectedElements;
                goto Step1;
            }
            else
            {
                goto Step0;
            }



            Step0:
            List<LcElement> InputElements = new List<LcElement>();
            var step0 = curMethod.Steps[0];
            var result0 = await ElementInputers.Execute(step0.Options);
            this.selectedElements = (List<LcElement>)result0.ValueX;
            if (selectedElements.Count > 0)
            {
                goto Step1;
            }
            else
                goto Step0;

            Step1:
            var step1 = curMethod.Steps[1];
            var result1 = await PointInputer.Execute(step1.Options);

            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }

            // zcb: 增加Res0为空的判定
            if (result1 == null)
            {
                this.Cancel();
                return;
            }

            if (result1.ValueX == null)
            {
                if (result1.Option != null)
                {
                }
                else
                    goto Step1;
            }
            this.basePoint = (Vector2)result1.ValueX;
            goto Step2;
            Step2:
            this.vportRt.SetTransformDrawer(this);
            var step2 = curMethod.Steps[2];
            var result2 = await PointInputer.Execute(step2.Options);
            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }
            if (result2.Option != null)
            {
                if (result2.Option.ToUpper() == "C")
                {
                    copy = true;
                    goto Step2;
                }
                length = Convert.ToDouble(result2.Option.ToString());
                //TODO:AutoCAD画线输入一个数字，是怎么确定点的？
            }
            else
                scalePoint = (Vector2)result2.ValueX;
            this.vportRt.SetTransformDrawer(null);
            goto End;
            End:
            foreach (LcElement item in this.selectedElements)
            {
                if (length == 0)
                {
                    if (copy)
                    {
                        (item.RtAction as ElementAction).CreateElement(item, basePoint, scalePoint);
                    }
                    else
                        item.Scale(basePoint, scalePoint);
                }
                else
                {
                    if (copy)
                    {
                        (item.RtAction as ElementAction).CreateElement(item,basePoint,length);
                    }
                    else
                        item.Scale(basePoint, length);
                }
            }
            this.EndAction();
        }
        public async void RotateTransform(string[] args)
        {
            this.StartAction();
            Vector2 rotatePoint;
            bool copy = false;
            
            this.CurrentTransform = "ROTATE";
            var curMethod = CreateMethods[1];
            this.ElementInputers = new ElementSetInputer(this.docEditor);
            this.CmdTextInputer = new CmdTextInputer(this.docEditor);
            this.PointInputer = new PointInputer(this.docEditor);
            double length = 0;

            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                this.selectedElements = this.docRt.Action.SelectedElements;
                goto Step1;
            }
            else
            {
                goto Step0;
            }

            Step0:
            List<LcElement> InputElements = new List<LcElement>();
            var step0 = curMethod.Steps[0];
            var result0 = await ElementInputers.Execute(step0.Options);
            if (result0 == null || result0.IsCancelled)
            {
                this.Cancel();
                return;
            }
            this.selectedElements = (List<LcElement>)result0.ValueX;
            if (selectedElements.Count > 0)
            {
                goto Step1;
            }
            else
                goto Step0;

            Step1:
            var step1 = curMethod.Steps[1];
            var result1 = await PointInputer.Execute(step1.Options);

            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }
            if (result1 == null || result1.IsCancelled)
            {
                this.Cancel();
                return;
            }
            if (result1.ValueX == null)
            {
                if (result1.Option != null)
                {
              
                }
                else
                    goto Step1;
            }
            basePoint = (Vector2)result1.ValueX;
            goto Step2;
            Step2:
            this.vportRt.SetTransformDrawer(this);
            var step2 = curMethod.Steps[2];
            var result2 = await PointInputer.Execute(step2.Options);
            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }

            if (result2.Option != null)
            {
                if (result2.Option.ToUpper() == "C")
                {
                    copy = true;
                    goto Step2;
                }
                length = Convert.ToDouble(result2.Option.ToString());
            }
            rotatePoint = (Vector2)result2.ValueX;
            this.vportRt.SetTransformDrawer(null);
            goto End;
            End:
            foreach (LcElement item in this.selectedElements)
            {
                var rotateAngle = Vector2.GetAngle(basePoint, rotatePoint);
                if (copy)
                {
                    Matrix3 matrix3 = Matrix3.RotateInRadian(rotateAngle, basePoint);
                    (item.RtAction as ElementAction).CreateElement(item, matrix3);
                }
                else
                {
                   
                    item.Rotate(basePoint, rotateAngle);
                }
            }
            this.EndAction();
        }
        public async void MoveTransform(string[] args)
        {
            this.StartAction();
            bool copy = false;
            Vector2 endPoint;
            this.CurrentTransform = "MOVE";
            var curMethod = CreateMethods[2];
            this.ElementInputers = new ElementSetInputer(this.docEditor);
            this.CmdTextInputer = new CmdTextInputer(this.docEditor);
            this.PointInputer = new PointInputer(this.docEditor);
            double length = 0;

            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                this.selectedElements = this.docRt.Action.SelectedElements;
                goto Step1;
            }
            else
            {
                goto Step0;
            }

            Step0:
            List<LcElement> InputElements = new List<LcElement>();
            var step0 = curMethod.Steps[0];
            var result0 = await ElementInputers.Execute(step0.Options);
            if(ElementInputers.isCancelled)
            {
                this.Cancel();
                return;
            }
            this.selectedElements = (List<LcElement>)result0.ValueX;
            if (selectedElements.Count > 0)
            {
                goto Step1;
            }
            else
                goto Step0;

            Step1:
            var step1 = curMethod.Steps[1];
            var result1 = await PointInputer.Execute(step1.Options);

            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }
            if (result1 == null)
            {
                this.Cancel();
                return;
            }
            if (result1.ValueX == null)
            {
                if (result1.Option != null)
                {
                    
                }
                else
                    goto Step1;
            }
            basePoint = (Vector2)result1.ValueX;
            goto Step2;
            Step2:
            this.vportRt.SetTransformDrawer(this);
            var step2 = curMethod.Steps[2];
            var result2 = await PointInputer.Execute(step2.Options);
            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }

            if (result2.Option != null)
            {
                if (result2.Option.ToUpper() == "C")
                {
                    copy = true;
                    goto Step2;
                }
                if (!double.TryParse(result2.Option.ToString(),out length))
                {
                    goto Step2;
                }
            }
            endPoint = (Vector2)result2.ValueX;
            this.vportRt.SetTransformDrawer(null);
            goto End;
            End:
            foreach (LcElement item in this.selectedElements)
            {
               
                if (copy)
                {
                    Matrix3 matrix3 = Matrix3.GetMove(basePoint, endPoint);
                    (item.RtAction as ElementAction).CreateElement(item, matrix3);
                }
                else
                {
                    item.Move(basePoint, endPoint);
                }

            }
            this.EndAction();
        }
        public async void MirrorTransform(string[] args)
        {
            this.StartAction();
            Vector2 endPoint;
            bool copy = false;
            this.CurrentTransform = "MIRROR";
            var curMethod = CreateMethods[3];
            this.ElementInputers = new ElementSetInputer(this.docEditor);
            this.CmdTextInputer = new CmdTextInputer(this.docEditor);
            this.PointInputer = new PointInputer(this.docEditor);
            double length = 0;

            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                this.selectedElements = this.docRt.Action.SelectedElements;
                goto Step1;
            }
            else
            {
                goto Step0;
            }

            Step0:
            List<LcElement> InputElements = new List<LcElement>();
            var step0 = curMethod.Steps[0];
            var result0 = await ElementInputers.Execute(step0.Options);
            if (ElementInputers.isCancelled)
            {
                this.Cancel();
                return;
            }
            this.selectedElements = (List<LcElement>)result0.ValueX;
            if (selectedElements.Count > 0)
            {
                goto Step1;
            }
            else
                goto Step0;

            Step1:
            var step1 = curMethod.Steps[1];
            var result1 = await PointInputer.Execute(step1.Options);

            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }
            if (result1 == null)
            {
                this.Cancel();
                return;
            }
            if (result1.ValueX == null)
            {
                if (result1.Option != null)
                {
                     
                }
                else
                    goto Step1;
            }
            basePoint = (Vector2)result1.ValueX;
            goto Step2;
            Step2:
            this.vportRt.SetTransformDrawer(this);
            var step2 = curMethod.Steps[2];
            var result2 = await PointInputer.Execute(step2.Options);
            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }

            if (result2.Option != null)
            {
                if (result2.Option.ToUpper() == "C")
                {
                    copy = true;
                    goto Step2;
                }
                length = Convert.ToDouble(result2.Option.ToString());
            }
            endPoint = (Vector2)result2.ValueX;
    
            goto End;
            End:
            foreach (LcElement item in this.selectedElements)
            {
                var eleAction = (item.RtAction as ElementAction);
                if(item is IComponentInstance)
                {
                    var newCptIns = item.Clone();
                    newCptIns.Mirror(basePoint, endPoint);
                    newCptIns.Initilize(this.vportRt.ActiveElementSet.Document);
                    this.vportRt.ActiveElementSet.InsertElement(newCptIns);
                }
                else
                {
                    if (copy)
                    {
                        Matrix3 matrix3 = Matrix3.GetMirror(basePoint, endPoint);
                        //matrix3.MultiplyPoint()
                        eleAction.CreateElement(item, matrix3);
                    }
                    else
                    {
                        item.Mirror(basePoint, endPoint);
                    }
                }
              
            }
            this.EndAction();
        }
        public virtual void DrawTrans(SKCanvas canvas)
        {
            switch (this.CurrentTransform)
            {
                case "SCALE": DrawScale(canvas); break;
                case "ROTATE": DrawRotate(canvas); break;
                case "MIRROR": DrawMirror(canvas); break;
                case "MOVE": DrawMove(canvas); break;
            }
        }
        public void DrawScale(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            Matrix3 matrix3 = Matrix3.GetScale(wcs_mp, basePoint);
            DrawAuxLine(canvas);
            foreach (var item in selectedElements)
            {
                var eleAction = (item.RtAction as ElementAction);
                eleAction.Draw(canvas, item, matrix3);
            }
        }
        public void DrawMove(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            DrawAuxLine(canvas);
            Matrix3 matrix3 = Matrix3.GetMove(basePoint, wcs_mp);
            foreach (var item in selectedElements)
            {
                var eleAction = (item.RtAction as ElementAction);
                eleAction.Draw(canvas, item, matrix3);
            }

        }
        public void DrawRotate(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            var Angle = Vector2.GetAngle(basePoint, wcs_mp);
            Matrix3 matrix3 = Matrix3.RotateInRadian(Angle, basePoint);
            DrawAuxLine(canvas);
            foreach (var item in selectedElements)
            {
                var eleAction = (item.RtAction as ElementAction);
                eleAction.Draw(canvas, item, matrix3);
            }

        }
        public void DrawMirror(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            var Angle = Vector2.GetAngle(basePoint, wcs_mp);
            //  Matrix3 matrix3 = Matrix3.RotateInRadian(Angle, basePoint);
            Matrix3 matrix4 = Matrix3.GetMirror(wcs_mp, basePoint);
            DrawAuxLine(canvas);
            foreach (var item in selectedElements)
            {
                var eleAction = (item.RtAction as ElementAction);
                eleAction.Draw(canvas, item, matrix4);
            }

        }
        public void DrawAuxLine(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            var sk_pre = this.vportRt.ConvertWcsToScr(basePoint).ToSKPoint();
            var sk_p = this.vportRt.ConvertWcsToScr(wcs_mp).ToSKPoint();
            SKPaint AuxPen = new SKPaint { Color = SKColors.Gray, IsStroke = true, PathEffect = Constants.SelectedEffect };
            canvas.DrawLine(sk_pre, sk_p, AuxPen);
        }
        private void OnInputKeyUp(KeyEventRuntime runtime)
        {
            throw new NotImplementedException();
        }

        private void OnInputKeyDown(KeyEventRuntime runtime)
        {
            throw new NotImplementedException();
        }

        private void OnViewportKeyDown(KeyEventRuntime runtime)
        {
            throw new NotImplementedException();
        }

        private void OnViewportMouseEvent(string arg1, MouseEventRuntime runtime)
        {
            throw new NotImplementedException();
        }

        protected void DetachEvents()
        {

            //    vportRt.Control.DetachEvents(this.OnViewportMouseEvent, this.OnViewportKeyDown);
            //docRt.Commander.DetachInputEvent(OnInputKeyDown, OnInputKeyUp);
        }
        public void Cancel()
        {
            this.DetachEvents();
            //TODO:
            this.EndAction();
        }

        public void StartAction()
        {
            if (vportRt.CheckStatus(ViewportStatus.InAction))
            {
                vportRt.CancelCurrentAction();
            }
            vportRt.SetStatus(ViewportStatus.InAction);
            this.vportRt.CommandCenter.InAction = true;
        }

        public void EndAction()
        {
            this.vportRt.SetTransformDrawer(null);
            vportRt.ClearStatus();
            this.commandCtrl.Prompt(string.Empty);
 
            this.vportRt.CurrentAction = null;
            this.vportRt.CursorType = LcCursorType.SelectElement;
            this.vportRt.CursorAddon = CursorAddonType.None;
            this.vportRt.CommandCenter.InAction = false;
            this.vportRt.CancelCurrentAction();
            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                this.docRt.Action.SetSelectsToDragging(false);
                this.vportRt.ClearElementGrips();
                this.docRt.Action.ClearSelects();
            }
        }

        public void DrawLengthen(SKCanvas canvas)
        {
            
        }
    }


}


